home *** CD-ROM | disk | FTP | other *** search
/ 3D GFX / 3D GFX.iso / amiutils / e_h / gd / gd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-12-31  |  58.9 KB  |  2,689 lines

  1. /*#include <malloc.h>*/
  2. #include <stdio.h>
  3. #include <math.h>
  4. #include <string.h>
  5. #include <stdlib.h>
  6. #include "gd.h"
  7. #include "mtables.c"
  8.  
  9. static void gdImageBrushApply(/* gdImagePtr im, int x, int y */);
  10. static void gdImageTileApply(/* gdImagePtr im, int x, int y */);
  11.  
  12. gdImagePtr gdImageCreate(sx, sy)
  13.     int sx;
  14.     int sy;
  15. {
  16.     int i;
  17.     gdImagePtr im;
  18.     im = (gdImage *) malloc(sizeof(gdImage));
  19.     im->pixels = (unsigned char **) malloc(sizeof(unsigned char *) * sx);
  20.     im->polyInts = 0;
  21.     im->polyAllocated = 0;
  22.     im->brush = 0;
  23.     im->tile = 0;
  24.     im->style = 0;
  25.     for (i=0; (i<sx); i++) {
  26.         im->pixels[i] = (unsigned char *) calloc(
  27.             sy, sizeof(unsigned char));
  28.     }    
  29.     im->sx = sx;
  30.     im->sy = sy;
  31.     im->colorsTotal = 0;
  32.     im->transparent = (-1);
  33.     im->interlace = 0;
  34.     return im;
  35. }
  36.  
  37. void gdImageDestroy(im)
  38.     gdImagePtr im;
  39. {
  40.     int i;
  41.     for (i=0; (i<im->sx); i++) {
  42.         free(im->pixels[i]);
  43.     }    
  44.     free(im->pixels);
  45.     if (im->polyInts) {
  46.             free(im->polyInts);
  47.     }
  48.     if (im->style) {
  49.         free(im->style);
  50.     }
  51.     free(im);
  52. }
  53.  
  54. int gdImageColorClosest(im, r, g, b)
  55.     gdImagePtr im;
  56.     int r;
  57.     int g;
  58.     int b; 
  59. {
  60.     int i;
  61.     long rd, gd, bd;
  62.     int ct = (-1);
  63.     long mindist;
  64.     for (i=0; (i<(im->colorsTotal)); i++) {
  65.         long dist;
  66.         if (im->open[i]) {
  67.             continue;
  68.         }
  69.         rd = (im->red[i] - r);    
  70.         gd = (im->green[i] - g);
  71.         bd = (im->blue[i] - b);
  72.         dist = rd * rd + gd * gd + bd * bd;
  73.         if ((i == 0) || (dist < mindist)) {
  74.             mindist = dist;    
  75.             ct = i;
  76.         }
  77.     }
  78.     return ct;
  79. }
  80.  
  81. int gdImageColorExact(im, r, g, b)
  82.     gdImagePtr im;
  83.     int r;
  84.     int g;
  85.     int b; 
  86. {
  87.     int i;
  88.     for (i=0; (i<(im->colorsTotal)); i++) {
  89.         if (im->open[i]) {
  90.             continue;
  91.         }
  92.         if ((im->red[i] == r) && 
  93.             (im->green[i] == g) &&
  94.             (im->blue[i] == b)) {
  95.             return i;
  96.         }
  97.     }
  98.     return -1;
  99. }
  100.  
  101. int gdImageColorAllocate(im, r, g, b)
  102.     gdImagePtr im;
  103.     int r;
  104.     int g;
  105.     int b; 
  106. {
  107.     int i;
  108.     int ct = (-1);
  109.     for (i=0; (i<(im->colorsTotal)); i++) {
  110.         if (im->open[i]) {
  111.             ct = i;
  112.             break;
  113.         }
  114.     }    
  115.     if (ct == (-1)) {
  116.         ct = im->colorsTotal;
  117.         if (ct == gdMaxColors) {
  118.             return -1;
  119.         }
  120.         im->colorsTotal++;
  121.     }
  122.     im->red[ct] = r;
  123.     im->green[ct] = g;
  124.     im->blue[ct] = b;
  125.     im->open[ct] = 0;
  126.     return ct;
  127. }
  128.  
  129. void gdImageColorDeallocate(im, color)
  130.     gdImagePtr im;
  131.     int color;
  132. {
  133.     /* Mark it open. */
  134.     im->open[color] = 1;
  135. }
  136.  
  137. void gdImageColorTransparent(im, color)
  138.     gdImagePtr im;
  139.     int color;
  140. {
  141.     im->transparent = color;
  142. }
  143.  
  144. void gdImageSetPixel(im, x, y, color)
  145.     gdImagePtr im;
  146.     int x; 
  147.     int y;
  148.     int color;
  149. {
  150.     int p;
  151.     switch(color) {
  152.         case gdStyled:
  153.         if (!im->style) {
  154.             /* Refuse to draw if no style is set. */
  155.             return;
  156.         } else {
  157.             p = im->style[im->stylePos++];
  158.         }
  159.         if (p != (gdTransparent)) {
  160.             gdImageSetPixel(im, x, y, p);
  161.         }
  162.         im->stylePos = im->stylePos %  im->styleLength;
  163.         break;
  164.         case gdStyledBrushed:
  165.         if (!im->style) {
  166.             /* Refuse to draw if no style is set. */
  167.             return;
  168.         }
  169.         p = im->style[im->stylePos++];
  170.         if ((p != gdTransparent) && (p != 0)) {
  171.             gdImageSetPixel(im, x, y, gdBrushed);
  172.         }
  173.         im->stylePos = im->stylePos %  im->styleLength;
  174.         break;
  175.         case gdBrushed:
  176.         gdImageBrushApply(im, x, y);
  177.         break;
  178.         case gdTiled:
  179.         gdImageTileApply(im, x, y);
  180.         break;
  181.         default:
  182.         if (gdImageBoundsSafe(im, x, y)) {
  183.              im->pixels[x][y] = color;
  184.         }
  185.         break;
  186.     }
  187. }
  188.  
  189. static void gdImageBrushApply(im, x, y)
  190.     gdImagePtr im;
  191.     int x;
  192.     int y;
  193. {
  194.     int lx, ly;
  195.     int hy;
  196.     int hx;
  197.     int x1, y1, x2, y2;
  198.     int srcx, srcy;
  199.     if (!im->brush) {
  200.         return;
  201.     }
  202.     hy = gdImageSY(im->brush)/2;
  203.     y1 = y - hy;
  204.     y2 = y1 + gdImageSY(im->brush);    
  205.     hx = gdImageSX(im->brush)/2;
  206.     x1 = x - hx;
  207.     x2 = x1 + gdImageSX(im->brush);
  208.     srcy = 0;
  209.     for (ly = y1; (ly < y2); ly++) {
  210.         srcx = 0;
  211.         for (lx = x1; (lx < x2); lx++) {
  212.             int p;
  213.             p = gdImageGetPixel(im->brush, srcx, srcy);
  214.             /* Allow for non-square brushes! */
  215.             if (p != gdImageGetTransparent(im->brush)) {
  216.                 gdImageSetPixel(im, lx, ly,
  217.                     im->brushColorMap[p]);
  218.             }
  219.             srcx++;
  220.         }
  221.         srcy++;
  222.     }    
  223. }        
  224.  
  225. static void gdImageTileApply(im, x, y)
  226.     gdImagePtr im;
  227.     int x;
  228.     int y;
  229. {
  230.     int srcx, srcy;
  231.     int p;
  232.     if (!im->tile) {
  233.         return;
  234.     }
  235.     srcx = x % gdImageSX(im->tile);
  236.     srcy = y % gdImageSY(im->tile);
  237.     p = gdImageGetPixel(im->tile, srcx, srcy);
  238.     /* Allow for transparency */
  239.     if (p != gdImageGetTransparent(im->tile)) {
  240.         gdImageSetPixel(im, x, y,
  241.             im->tileColorMap[p]);
  242.     }
  243. }        
  244.  
  245. int gdImageGetPixel(im, x, y)
  246.     gdImagePtr im; 
  247.     int x; 
  248.     int y; 
  249. {
  250.     if (gdImageBoundsSafe(im, x, y)) {
  251.         return im->pixels[x][y];
  252.     } else {
  253.         return 0;
  254.     }
  255. }
  256.  
  257. /* Bresenham as presented in Foley & Van Dam */
  258.  
  259. void gdImageLine(im, x1, y1, x2, y2, color)
  260.     gdImagePtr im;
  261.     int x1;
  262.     int y1;
  263.     int x2;
  264.     int y2;
  265.     int color; 
  266. {
  267.     int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag;
  268.     dx = abs(x2-x1);
  269.     dy = abs(y2-y1);
  270.     if (dy <= dx) {
  271.         d = 2*dy - dx;
  272.         incr1 = 2*dy;
  273.         incr2 = 2 * (dy - dx);
  274.         if (x1 > x2) {
  275.             x = x2;
  276.             y = y2;
  277.             ydirflag = (-1);
  278.             xend = x1;
  279.         } else {
  280.             x = x1;
  281.             y = y1;
  282.             ydirflag = 1;
  283.             xend = x2;
  284.         }
  285.         gdImageSetPixel(im, x, y, color);
  286.         if (((y2 - y1) * ydirflag) > 0) {
  287.             while (x < xend) {
  288.                 x++;
  289.                 if (d <0) {
  290.                     d+=incr1;
  291.                 } else {
  292.                     y++;
  293.                     d+=incr2;
  294.                 }
  295.                 gdImageSetPixel(im, x, y, color);
  296.             }
  297.         } else {
  298.             while (x < xend) {
  299.                 x++;
  300.                 if (d <0) {
  301.                     d+=incr1;
  302.                 } else {
  303.                     y--;
  304.                     d+=incr2;
  305.                 }
  306.                 gdImageSetPixel(im, x, y, color);
  307.             }
  308.         }        
  309.     } else {
  310.         d = 2*dx - dy;
  311.         incr1 = 2*dx;
  312.         incr2 = 2 * (dx - dy);
  313.         if (y1 > y2) {
  314.             y = y2;
  315.             x = x2;
  316.             yend = y1;
  317.             xdirflag = (-1);
  318.         } else {
  319.             y = y1;
  320.             x = x1;
  321.             yend = y2;
  322.             xdirflag = 1;
  323.         }
  324.         gdImageSetPixel(im, x, y, color);
  325.         if (((x2 - x1) * xdirflag) > 0) {
  326.             while (y < yend) {
  327.                 y++;
  328.                 if (d <0) {
  329.                     d+=incr1;
  330.                 } else {
  331.                     x++;
  332.                     d+=incr2;
  333.                 }
  334.                 gdImageSetPixel(im, x, y, color);
  335.             }
  336.         } else {
  337.             while (y < yend) {
  338.                 y++;
  339.                 if (d <0) {
  340.                     d+=incr1;
  341.                 } else {
  342.                     x--;
  343.                     d+=incr2;
  344.                 }
  345.                 gdImageSetPixel(im, x, y, color);
  346.             }
  347.         }
  348.     }
  349. }
  350.  
  351. /* As above, plus dashing */
  352.  
  353. #define dashedSet \
  354.     { \
  355.         dashStep++; \
  356.         if (dashStep == gdDashSize) { \
  357.             dashStep = 0; \
  358.             on = !on; \
  359.         } \
  360.         if (on) { \
  361.             gdImageSetPixel(im, x, y, color); \
  362.         } \
  363.     }
  364.  
  365. void gdImageDashedLine(im, x1, y1, x2, y2, color)
  366.     gdImagePtr im;
  367.     int x1;
  368.     int y1;
  369.     int x2;
  370.     int y2;
  371.     int color; 
  372. {
  373.     int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag;
  374.     int dashStep = 0;
  375.     int on = 1;
  376.     dx = abs(x2-x1);
  377.     dy = abs(y2-y1);
  378.     if (dy <= dx) {
  379.         d = 2*dy - dx;
  380.         incr1 = 2*dy;
  381.         incr2 = 2 * (dy - dx);
  382.         if (x1 > x2) {
  383.             x = x2;
  384.             y = y2;
  385.             ydirflag = (-1);
  386.             xend = x1;
  387.         } else {
  388.             x = x1;
  389.             y = y1;
  390.             ydirflag = 1;
  391.             xend = x2;
  392.         }
  393.         dashedSet;
  394.         if (((y2 - y1) * ydirflag) > 0) {
  395.             while (x < xend) {
  396.                 x++;
  397.                 if (d <0) {
  398.                     d+=incr1;
  399.                 } else {
  400.                     y++;
  401.                     d+=incr2;
  402.                 }
  403.                 dashedSet;
  404.             }
  405.         } else {
  406.             while (x < xend) {
  407.                 x++;
  408.                 if (d <0) {
  409.                     d+=incr1;
  410.                 } else {
  411.                     y--;
  412.                     d+=incr2;
  413.                 }
  414.                 dashedSet;
  415.             }
  416.         }        
  417.     } else {
  418.         d = 2*dx - dy;
  419.         incr1 = 2*dx;
  420.         incr2 = 2 * (dx - dy);
  421.         if (y1 > y2) {
  422.             y = y2;
  423.             x = x2;
  424.             yend = y1;
  425.             xdirflag = (-1);
  426.         } else {
  427.             y = y1;
  428.             x = x1;
  429.             yend = y2;
  430.             xdirflag = 1;
  431.         }
  432.         dashedSet;
  433.         if (((x2 - x1) * xdirflag) > 0) {
  434.             while (y < yend) {
  435.                 y++;
  436.                 if (d <0) {
  437.                     d+=incr1;
  438.                 } else {
  439.                     x++;
  440.                     d+=incr2;
  441.                 }
  442.                 dashedSet;
  443.             }
  444.         } else {
  445.             while (y < yend) {
  446.                 y++;
  447.                 if (d <0) {
  448.                     d+=incr1;
  449.                 } else {
  450.                     x--;
  451.                     d+=incr2;
  452.                 }
  453.                 dashedSet;
  454.             }
  455.         }
  456.     }
  457. }
  458.  
  459. int gdImageBoundsSafe(im, x, y)
  460.     gdImagePtr im;
  461.     int x;
  462.     int y; 
  463. {
  464.     return (!(((y < 0) || (y >= im->sy)) ||
  465.         ((x < 0) || (x >= im->sx))));
  466. }
  467.  
  468. void gdImageChar(im, f, x, y, c, color)
  469.     gdImagePtr im; 
  470.     gdFontPtr f;
  471.     int x;
  472.     int y;
  473.     int c;
  474.     int color;
  475. {
  476.     int cx, cy;
  477.     int px, py;
  478.     int fline;
  479.     cx = 0;
  480.     cy = 0;
  481.     if ((c < f->offset) || (c >= (f->offset + f->nchars))) {
  482.         return;
  483.     }
  484.     fline = (c - f->offset) * f->h * f->w;
  485.     for (py = y; (py < (y + f->h)); py++) {
  486.         for (px = x; (px < (x + f->w)); px++) {
  487.             if (f->data[fline + cy * f->w + cx]) {
  488.                 gdImageSetPixel(im, px, py, color);    
  489.             }
  490.             cx++;
  491.         }
  492.         cx = 0;
  493.         cy++;
  494.     }
  495. }
  496.  
  497. void gdImageCharUp(im, f, x, y, c, color)
  498.     gdImagePtr im; 
  499.     gdFontPtr f;
  500.     int x;
  501.     int y;
  502.     char c;
  503.     int color;
  504. {
  505.     int cx, cy;
  506.     int px, py;
  507.     int fline;
  508.     cx = 0;
  509.     cy = 0;
  510.     if ((c < f->offset) || (c >= (f->offset + f->nchars))) {
  511.         return;
  512.     }
  513.     fline = (c - f->offset) * f->h * f->w;
  514.     for (py = y; (py > (y - f->w)); py--) {
  515.         for (px = x; (px < (x + f->h)); px++) {
  516.             if (f->data[fline + cy * f->w + cx]) {
  517.                 gdImageSetPixel(im, px, py, color);    
  518.             }
  519.             cy++;
  520.         }
  521.         cy = 0;
  522.         cx++;
  523.     }
  524. }
  525.  
  526. void gdImageString(im, f, x, y, s, color)
  527.     gdImagePtr im;
  528.     gdFontPtr f;
  529.     int x;
  530.     int y;
  531.     char *s;
  532.     int color;
  533. {
  534.     int i;
  535.     int l;
  536.     l = strlen(s);
  537.     for (i=0; (i<l); i++) {
  538.         gdImageChar(im, f, x, y, s[i], color);
  539.         x += f->w;
  540.     }
  541. }
  542.  
  543. void gdImageStringUp(im, f, x, y, s, color)
  544.     gdImagePtr im;
  545.     gdFontPtr f;
  546.     int x;
  547.     int y;
  548.     char *s;
  549.     int color;
  550. {
  551.     int i;
  552.     int l;
  553.     l = strlen(s);
  554.     for (i=0; (i<l); i++) {
  555.         gdImageCharUp(im, f, x, y, s[i], color);
  556.         y -= f->w;
  557.     }
  558. }
  559.  
  560. /* s and e are integers modulo 360 (degrees), with 0 degrees
  561.   being the rightmost extreme and degrees changing clockwise.
  562.   cx and cy are the center in pixels; w and h are the horizontal 
  563.   and vertical diameter in pixels. Nice interface, but slow, since
  564.   I don't yet use Bresenham (I'm using an inefficient but
  565.   simple solution with too much work going on in it; generalizing
  566.   Bresenham to ellipses and partial arcs of ellipses is non-trivial,
  567.   at least for me) and there are other inefficiencies (small circles
  568.   do far too much work). */
  569.  
  570. void gdImageArc(im, cx, cy, w, h, s, e, color)
  571.     gdImagePtr im;
  572.     int cx;
  573.     int cy;
  574.     int w;
  575.     int h;
  576.     int s;
  577.     int e;
  578.     int color;
  579. {
  580.     int i;
  581.     int smod, emod;
  582.     int lx, ly;
  583.     int w2, h2;
  584.     w2 = w/2;
  585.     h2 = h/2;
  586.     while (e < s) {
  587.         e += 360;
  588.     }
  589.     for (i=s; (i <= e); i++) {
  590.         int x, y;
  591.         x = ((long)cost[i % 360] * (long)w2 / costScale) + cx; 
  592.         y = ((long)sint[i % 360] * (long)h2 / sintScale) + cy;
  593.         if (i != s) {
  594.             gdImageLine(im, lx, ly, x, y, color);    
  595.         }
  596.         lx = x;
  597.         ly = y;
  598.     }
  599. }
  600.  
  601.  
  602. #if 0
  603.     /* Bresenham octant code, which I should use eventually */
  604.     int x, y, d;
  605.     x = 0;
  606.     y = w;
  607.     d = 3-2*w;
  608.     while (x < y) {
  609.         gdImageSetPixel(im, cx+x, cy+y, color);
  610.         if (d < 0) {
  611.             d += 4 * x + 6;
  612.         } else {
  613.             d += 4 * (x - y) + 10;
  614.             y--;
  615.         }
  616.         x++;
  617.     }
  618.     if (x == y) {
  619.         gdImageSetPixel(im, cx+x, cy+y, color);
  620.     }
  621. #endif
  622.  
  623. void gdImageFillToBorder(im, x, y, border, color)
  624.     gdImagePtr im;
  625.     int x;
  626.     int y;
  627.     int border;
  628.     int color;
  629. {
  630.     int lastBorder;
  631.     /* Seek left */
  632.     int leftLimit, rightLimit;
  633.     int i;
  634.     leftLimit = (-1);
  635.     if (border < 0) {
  636.         /* Refuse to fill to a non-solid border */
  637.         return;
  638.     }
  639.     for (i = x; (i >= 0); i--) {
  640.         if (gdImageGetPixel(im, i, y) == border) {
  641.             break;
  642.         }
  643.         gdImageSetPixel(im, i, y, color);
  644.         leftLimit = i;
  645.     }
  646.     if (leftLimit == (-1)) {
  647.         return;
  648.     }
  649.     /* Seek right */
  650.     rightLimit = x;
  651.     for (i = (x+1); (i < im->sx); i++) {    
  652.         if (gdImageGetPixel(im, i, y) == border) {
  653.             break;
  654.         }
  655.         gdImageSetPixel(im, i, y, color);
  656.         rightLimit = i;
  657.     }
  658.     /* Look at lines above and below and start paints */
  659.     /* Above */
  660.     if (y > 0) {
  661.         lastBorder = 1;
  662.         for (i = leftLimit; (i <= rightLimit); i++) {
  663.             int c;
  664.             c = gdImageGetPixel(im, i, y-1);
  665.             if (lastBorder) {
  666.                 if ((c != border) && (c != color)) {    
  667.                     gdImageFillToBorder(im, i, y-1, 
  668.                         border, color);        
  669.                     lastBorder = 0;
  670.                 }
  671.             } else if ((c == border) || (c == color)) {
  672.                 lastBorder = 1;
  673.             }
  674.         }
  675.     }
  676.     /* Below */
  677.     if (y < ((im->sy) - 1)) {
  678.         lastBorder = 1;
  679.         for (i = leftLimit; (i <= rightLimit); i++) {
  680.             int c;
  681.             c = gdImageGetPixel(im, i, y+1);
  682.             if (lastBorder) {
  683.                 if ((c != border) && (c != color)) {    
  684.                     gdImageFillToBorder(im, i, y+1, 
  685.                         border, color);        
  686.                     lastBorder = 0;
  687.                 }
  688.             } else if ((c == border) || (c == color)) {
  689.                 lastBorder = 1;
  690.             }
  691.         }
  692.     }
  693. }
  694.  
  695. void gdImageFill(im, x, y, color)
  696.     gdImagePtr im;
  697.     int x;
  698.     int y;
  699.     int color;        
  700. {
  701.     int lastBorder;
  702.     int old;
  703.     int leftLimit, rightLimit;
  704.     int i;
  705.     old = gdImageGetPixel(im, x, y);
  706.     if (color == gdTiled) {
  707.         /* Tile fill -- got to watch out! */
  708.         int p, tileColor;    
  709.         int srcx, srcy;
  710.         if (!im->tile) {
  711.             return;
  712.         }
  713.         /* Refuse to flood-fill with a transparent pattern --
  714.             I can't do it without allocating another image */
  715.         if (gdImageGetTransparent(im->tile) != (-1)) {
  716.             return;
  717.         }    
  718.         srcx = x % gdImageSX(im->tile);
  719.         srcy = y % gdImageSY(im->tile);
  720.         p = gdImageGetPixel(im->tile, srcx, srcy);
  721.         tileColor = im->tileColorMap[p];
  722.         if (old == tileColor) {
  723.             /* Nothing to be done */
  724.             return;
  725.         }
  726.     } else {
  727.         if (old == color) {
  728.             /* Nothing to be done */
  729.             return;
  730.         }
  731.     }
  732.     /* Seek left */
  733.     leftLimit = (-1);
  734.     for (i = x; (i >= 0); i--) {
  735.         if (gdImageGetPixel(im, i, y) != old) {
  736.             break;
  737.         }
  738.         gdImageSetPixel(im, i, y, color);
  739.         leftLimit = i;
  740.     }
  741.     if (leftLimit == (-1)) {
  742.         return;
  743.     }
  744.     /* Seek right */
  745.     rightLimit = x;
  746.     for (i = (x+1); (i < im->sx); i++) {    
  747.         if (gdImageGetPixel(im, i, y) != old) {
  748.             break;
  749.         }
  750.         gdImageSetPixel(im, i, y, color);
  751.         rightLimit = i;
  752.     }
  753.     /* Look at lines above and below and start paints */
  754.     /* Above */
  755.     if (y > 0) {
  756.         lastBorder = 1;
  757.         for (i = leftLimit; (i <= rightLimit); i++) {
  758.             int c;
  759.             c = gdImageGetPixel(im, i, y-1);
  760.             if (lastBorder) {
  761.                 if (c == old) {    
  762.                     gdImageFill(im, i, y-1, color);        
  763.                     lastBorder = 0;
  764.                 }
  765.             } else if (c != old) {
  766.                 lastBorder = 1;
  767.             }
  768.         }
  769.     }
  770.     /* Below */
  771.     if (y < ((im->sy) - 1)) {
  772.         lastBorder = 1;
  773.         for (i = leftLimit; (i <= rightLimit); i++) {
  774.             int c;
  775.             c = gdImageGetPixel(im, i, y+1);
  776.             if (lastBorder) {
  777.                 if (c == old) {
  778.                     gdImageFill(im, i, y+1, color);        
  779.                     lastBorder = 0;
  780.                 }
  781.             } else if (c != old) {
  782.                 lastBorder = 1;
  783.             }
  784.         }
  785.     }
  786. }
  787.     
  788. #ifdef TEST_CODE
  789. void gdImageDump(im)
  790.     gdImagePtr im; 
  791. {
  792.     int i, j;
  793.     for (i=0; (i < im->sy); i++) {
  794.         for (j=0; (j < im->sx); j++) {
  795.             printf("%d", im->pixels[j][i]);
  796.         }
  797.         printf("\n");
  798.     }
  799. }
  800. #endif
  801.  
  802. /* Code drawn from ppmtogif.c, from the pbmplus package
  803. **
  804. ** Based on GIFENCOD by David Rowley <mgardi@watdscu.waterloo.edu>. A
  805. ** Lempel-Zim compression based on "compress".
  806. **
  807. ** Modified by Marcel Wijkstra <wijkstra@fwi.uva.nl>
  808. **
  809. ** Copyright (C) 1989 by Jef Poskanzer.
  810. **
  811. ** Permission to use, copy, modify, and distribute this software and its
  812. ** documentation for any purpose and without fee is hereby granted, provided
  813. ** that the above copyright notice appear in all copies and that both that
  814. ** copyright notice and this permission notice appear in supporting
  815. ** documentation.  This software is provided "as is" without express or
  816. ** implied warranty.
  817. **
  818. ** The Graphics Interchange Format(c) is the Copyright property of
  819. ** CompuServe Incorporated.  GIF(sm) is a Service Mark property of
  820. ** CompuServe Incorporated.
  821. */
  822.  
  823. /*
  824.  * a code_int must be able to hold 2**GIFBITS values of type int, and also -1
  825.  */
  826. typedef int             code_int;
  827.  
  828. #ifdef SIGNED_COMPARE_SLOW
  829. typedef unsigned long int count_int;
  830. typedef unsigned short int count_short;
  831. #else /*SIGNED_COMPARE_SLOW*/
  832. typedef long int          count_int;
  833. #endif /*SIGNED_COMPARE_SLOW*/
  834.  
  835. static int colorstobpp(/* int colors */);
  836. static void BumpPixel (/* void */);
  837. static int GIFNextPixel (/* gdImagePtr im */);
  838. static void GIFEncode (/* FILE* fp, int GWidth, int GHeight, int GInterlace, int Background, int Transparent, int BitsPerPixel, int* Red, int* Green, int* Blue, gdImagePtr im */);
  839. static void Putword (/* int w, FILE* fp */);
  840. static void compress (/* int init_bits, FILE* outfile, gdImagePtr im */);
  841. static void output (/* code_int code */);
  842. static void cl_block (/* void */);
  843. static void cl_hash (/* count_int hsize */);
  844. static void char_init (/* void */);
  845. static void char_out (/* int c */);
  846. static void flush_char (/* void */);
  847. /* Allows for reuse */
  848. static void init_statics(/* void */);
  849.  
  850. void gdImageGif(im, out)
  851.     gdImagePtr im; 
  852.     FILE *out;
  853. {
  854.     int interlace, transparent, BitsPerPixel;
  855.     interlace = im->interlace;
  856.     transparent = im->transparent;
  857.  
  858.     BitsPerPixel = colorstobpp(im->colorsTotal);
  859.     /* Clear any old values in statics strewn through the GIF code */
  860.     init_statics();
  861.     /* All set, let's do it. */
  862.     GIFEncode(
  863.         out, im->sx, im->sy, interlace, 0, transparent, BitsPerPixel,
  864.         im->red, im->green, im->blue, im);
  865. }
  866.  
  867. static int
  868. colorstobpp( colors )
  869. int colors;
  870.     {
  871.     int bpp;
  872.  
  873.     if ( colors <= 2 )
  874.         bpp = 1;
  875.     else if ( colors <= 4 )
  876.         bpp = 2;
  877.     else if ( colors <= 8 )
  878.         bpp = 3;
  879.     else if ( colors <= 16 )
  880.         bpp = 4;
  881.     else if ( colors <= 32 )
  882.         bpp = 5;
  883.     else if ( colors <= 64 )
  884.         bpp = 6;
  885.     else if ( colors <= 128 )
  886.         bpp = 7;
  887.     else if ( colors <= 256 )
  888.         bpp = 8;
  889.     return bpp;
  890.     }
  891.  
  892. /*****************************************************************************
  893.  *
  894.  * GIFENCODE.C    - GIF Image compression interface
  895.  *
  896.  * GIFEncode( FName, GHeight, GWidth, GInterlace, Background, Transparent,
  897.  *            BitsPerPixel, Red, Green, Blue, gdImagePtr )
  898.  *
  899.  *****************************************************************************/
  900.  
  901. #define TRUE 1
  902. #define FALSE 0
  903.  
  904. static int Width, Height;
  905. static int curx, cury;
  906. static long CountDown;
  907. static int Pass = 0;
  908. static int Interlace;
  909.  
  910. /*
  911.  * Bump the 'curx' and 'cury' to point to the next pixel
  912.  */
  913. static void
  914. BumpPixel()
  915. {
  916.         /*
  917.          * Bump the current X position
  918.          */
  919.         ++curx;
  920.  
  921.         /*
  922.          * If we are at the end of a scan line, set curx back to the beginning
  923.          * If we are interlaced, bump the cury to the appropriate spot,
  924.          * otherwise, just increment it.
  925.          */
  926.         if( curx == Width ) {
  927.                 curx = 0;
  928.  
  929.                 if( !Interlace )
  930.                         ++cury;
  931.                 else {
  932.                      switch( Pass ) {
  933.  
  934.                        case 0:
  935.                           cury += 8;
  936.                           if( cury >= Height ) {
  937.                                 ++Pass;
  938.                                 cury = 4;
  939.                           }
  940.                           break;
  941.  
  942.                        case 1:
  943.                           cury += 8;
  944.                           if( cury >= Height ) {
  945.                                 ++Pass;
  946.                                 cury = 2;
  947.                           }
  948.                           break;
  949.  
  950.                        case 2:
  951.                           cury += 4;
  952.                           if( cury >= Height ) {
  953.                              ++Pass;
  954.                              cury = 1;
  955.                           }
  956.                           break;
  957.  
  958.                        case 3:
  959.                           cury += 2;
  960.                           break;
  961.                         }
  962.                 }
  963.         }
  964. }
  965.  
  966. /*
  967.  * Return the next pixel from the image
  968.  */
  969. static int
  970. GIFNextPixel( im )
  971. gdImagePtr im;
  972. {
  973.         int r;
  974.  
  975.         if( CountDown == 0 )
  976.                 return EOF;
  977.  
  978.         --CountDown;
  979.  
  980.         r = gdImageGetPixel(im, curx, cury);
  981.  
  982.         BumpPixel();
  983.  
  984.         return r;
  985. }
  986.  
  987. /* public */
  988.  
  989. static void
  990. GIFEncode( fp, GWidth, GHeight, GInterlace, Background, Transparent,
  991.            BitsPerPixel, Red, Green, Blue, im )
  992.  
  993. FILE* fp;
  994. int GWidth, GHeight;
  995. int GInterlace;
  996. int Background;
  997. int Transparent;
  998. int BitsPerPixel;
  999. int Red[], Green[], Blue[];
  1000. gdImagePtr im;
  1001. {
  1002.         int B;
  1003.         int RWidth, RHeight;
  1004.         int LeftOfs, TopOfs;
  1005.         int Resolution;
  1006.         int ColorMapSize;
  1007.         int InitCodeSize;
  1008.         int i;
  1009.  
  1010.         Interlace = GInterlace;
  1011.  
  1012.         ColorMapSize = 1 << BitsPerPixel;
  1013.  
  1014.         RWidth = Width = GWidth;
  1015.         RHeight = Height = GHeight;
  1016.         LeftOfs = TopOfs = 0;
  1017.  
  1018.         Resolution = BitsPerPixel;
  1019.  
  1020.         /*
  1021.          * Calculate number of bits we are expecting
  1022.          */
  1023.         CountDown = (long)Width * (long)Height;
  1024.  
  1025.         /*
  1026.          * Indicate which pass we are on (if interlace)
  1027.          */
  1028.         Pass = 0;
  1029.  
  1030.         /*
  1031.          * The initial code size
  1032.          */
  1033.         if( BitsPerPixel <= 1 )
  1034.                 InitCodeSize = 2;
  1035.         else
  1036.                 InitCodeSize = BitsPerPixel;
  1037.  
  1038.         /*
  1039.          * Set up the current x and y position
  1040.          */
  1041.         curx = cury = 0;
  1042.  
  1043.         /*
  1044.          * Write the Magic header
  1045.          */
  1046.         fwrite( Transparent < 0 ? "GIF87a" : "GIF89a", 1, 6, fp );
  1047.  
  1048.         /*
  1049.          * Write out the screen width and height
  1050.          */
  1051.         Putword( RWidth, fp );
  1052.         Putword( RHeight, fp );
  1053.  
  1054.         /*
  1055.          * Indicate that there is a global colour map
  1056.          */
  1057.         B = 0x80;       /* Yes, there is a color map */
  1058.  
  1059.         /*
  1060.          * OR in the resolution
  1061.          */
  1062.         B |= (Resolution - 1) << 5;
  1063.  
  1064.         /*
  1065.          * OR in the Bits per Pixel
  1066.          */
  1067.         B |= (BitsPerPixel - 1);
  1068.  
  1069.         /*
  1070.          * Write it out
  1071.          */
  1072.         fputc( B, fp );
  1073.  
  1074.         /*
  1075.          * Write out the Background colour
  1076.          */
  1077.         fputc( Background, fp );
  1078.  
  1079.         /*
  1080.          * Byte of 0's (future expansion)
  1081.          */
  1082.         fputc( 0, fp );
  1083.  
  1084.         /*
  1085.          * Write out the Global Colour Map
  1086.          */
  1087.         for( i=0; i<ColorMapSize; ++i ) {
  1088.                 fputc( Red[i], fp );
  1089.                 fputc( Green[i], fp );
  1090.                 fputc( Blue[i], fp );
  1091.         }
  1092.  
  1093.     /*
  1094.      * Write out extension for transparent colour index, if necessary.
  1095.      */
  1096.     if ( Transparent >= 0 ) {
  1097.         fputc( '!', fp );
  1098.         fputc( 0xf9, fp );
  1099.         fputc( 4, fp );
  1100.         fputc( 1, fp );
  1101.         fputc( 0, fp );
  1102.         fputc( 0, fp );
  1103.         fputc( Transparent, fp );
  1104.         fputc( 0, fp );
  1105.     }
  1106.  
  1107.         /*
  1108.          * Write an Image separator
  1109.          */
  1110.         fputc( ',', fp );
  1111.  
  1112.         /*
  1113.          * Write the Image header
  1114.          */
  1115.  
  1116.         Putword( LeftOfs, fp );
  1117.         Putword( TopOfs, fp );
  1118.         Putword( Width, fp );
  1119.         Putword( Height, fp );
  1120.  
  1121.         /*
  1122.          * Write out whether or not the image is interlaced
  1123.          */
  1124.         if( Interlace )
  1125.                 fputc( 0x40, fp );
  1126.         else
  1127.                 fputc( 0x00, fp );
  1128.  
  1129.         /*
  1130.          * Write out the initial code size
  1131.          */
  1132.         fputc( InitCodeSize, fp );
  1133.  
  1134.         /*
  1135.          * Go and actually compress the data
  1136.          */
  1137.         compress( InitCodeSize+1, fp, im );
  1138.  
  1139.         /*
  1140.          * Write out a Zero-length packet (to end the series)
  1141.          */
  1142.         fputc( 0, fp );
  1143.  
  1144.         /*
  1145.          * Write the GIF file terminator
  1146.          */
  1147.         fputc( ';', fp );
  1148. }
  1149.  
  1150. /*
  1151.  * Write out a word to the GIF file
  1152.  */
  1153. static void
  1154. Putword( w, fp )
  1155. int w;
  1156. FILE* fp;
  1157. {
  1158.         fputc( w & 0xff, fp );
  1159.         fputc( (w / 256) & 0xff, fp );
  1160. }
  1161.  
  1162.  
  1163. /***************************************************************************
  1164.  *
  1165.  *  GIFCOMPR.C       - GIF Image compression routines
  1166.  *
  1167.  *  Lempel-Ziv compression based on 'compress'.  GIF modifications by
  1168.  *  David Rowley (mgardi@watdcsu.waterloo.edu)
  1169.  *
  1170.  ***************************************************************************/
  1171.  
  1172. /*
  1173.  * General DEFINEs
  1174.  */
  1175.  
  1176. #define GIFBITS    12
  1177.  
  1178. #define HSIZE  5003            /* 80% occupancy */
  1179.  
  1180. #ifdef NO_UCHAR
  1181.  typedef char   char_type;
  1182. #else /*NO_UCHAR*/
  1183.  typedef        unsigned char   char_type;
  1184. #endif /*NO_UCHAR*/
  1185.  
  1186. /*
  1187.  *
  1188.  * GIF Image compression - modified 'compress'
  1189.  *
  1190.  * Based on: compress.c - File compression ala IEEE Computer, June 1984.
  1191.  *
  1192.  * By Authors:  Spencer W. Thomas       (decvax!harpo!utah-cs!utah-gr!thomas)
  1193.  *              Jim McKie               (decvax!mcvax!jim)
  1194.  *              Steve Davies            (decvax!vax135!petsd!peora!srd)
  1195.  *              Ken Turkowski           (decvax!decwrl!turtlevax!ken)
  1196.  *              James A. Woods          (decvax!ihnp4!ames!jaw)
  1197.  *              Joe Orost               (decvax!vax135!petsd!joe)
  1198.  *
  1199.  */
  1200. #include <ctype.h>
  1201.  
  1202. #define ARGVAL() (*++(*argv) || (--argc && *++argv))
  1203.  
  1204. static int n_bits;                        /* number of bits/code */
  1205. static int maxbits = GIFBITS;                /* user settable max # bits/code */
  1206. static code_int maxcode;                  /* maximum code, given n_bits */
  1207. static code_int maxmaxcode = (code_int)1 << GIFBITS; /* should NEVER generate this code */
  1208. #ifdef COMPATIBLE               /* But wrong! */
  1209. # define MAXCODE(n_bits)        ((code_int) 1 << (n_bits) - 1)
  1210. #else /*COMPATIBLE*/
  1211. # define MAXCODE(n_bits)        (((code_int) 1 << (n_bits)) - 1)
  1212. #endif /*COMPATIBLE*/
  1213.  
  1214. static count_int htab [HSIZE];
  1215. static unsigned short codetab [HSIZE];
  1216. #define HashTabOf(i)       htab[i]
  1217. #define CodeTabOf(i)    codetab[i]
  1218.  
  1219. static code_int hsize = HSIZE;                 /* for dynamic table sizing */
  1220.  
  1221. /*
  1222.  * To save much memory, we overlay the table used by compress() with those
  1223.  * used by decompress().  The tab_prefix table is the same size and type
  1224.  * as the codetab.  The tab_suffix table needs 2**GIFBITS characters.  We
  1225.  * get this from the beginning of htab.  The output stack uses the rest
  1226.  * of htab, and contains characters.  There is plenty of room for any
  1227.  * possible stack (stack used to be 8000 characters).
  1228.  */
  1229.  
  1230. #define tab_prefixof(i) CodeTabOf(i)
  1231. #define tab_suffixof(i)        ((char_type*)(htab))[i]
  1232. #define de_stack               ((char_type*)&tab_suffixof((code_int)1<<GIFBITS))
  1233.  
  1234. static code_int free_ent = 0;                  /* first unused entry */
  1235.  
  1236. /*
  1237.  * block compression parameters -- after all codes are used up,
  1238.  * and compression rate changes, start over.
  1239.  */
  1240. static int clear_flg = 0;
  1241.  
  1242. static int offset;
  1243. static long int in_count = 1;            /* length of input */
  1244. static long int out_count = 0;           /* # of codes output (for debugging) */
  1245.  
  1246. /*
  1247.  * compress stdin to stdout
  1248.  *
  1249.  * Algorithm:  use open addressing double hashing (no chaining) on the
  1250.  * prefix code / next character combination.  We do a variant of Knuth's
  1251.  * algorithm D (vol. 3, sec. 6.4) along with G. Knott's relatively-prime
  1252.  * secondary probe.  Here, the modular division first probe is gives way
  1253.  * to a faster exclusive-or manipulation.  Also do block compression with
  1254.  * an adaptive reset, whereby the code table is cleared when the compression
  1255.  * ratio decreases, but after the table fills.  The variable-length output
  1256.  * codes are re-sized at this point, and a special CLEAR code is generated
  1257.  * for the decompressor.  Late addition:  construct the table according to
  1258.  * file size for noticeable speed improvement on small files.  Please direct
  1259.  * questions about this implementation to ames!jaw.
  1260.  */
  1261.  
  1262. static int g_init_bits;
  1263. static FILE* g_outfile;
  1264.  
  1265. static int ClearCode;
  1266. static int EOFCode;
  1267.  
  1268. static void
  1269. compress( init_bits, outfile, im )
  1270. int init_bits;
  1271. FILE* outfile;
  1272. gdImagePtr im;
  1273. {
  1274.     register long fcode;
  1275.     register code_int i /* = 0 */;
  1276.     register int c;
  1277.     register code_int ent;
  1278.     register code_int disp;
  1279.     register code_int hsize_reg;
  1280.     register int hshift;
  1281.  
  1282.     /*
  1283.      * Set up the globals:  g_init_bits - initial number of bits
  1284.      *                      g_outfile   - pointer to output file
  1285.      */
  1286.     g_init_bits = init_bits;
  1287.     g_outfile = outfile;
  1288.  
  1289.     /*
  1290.      * Set up the necessary values
  1291.      */
  1292.     offset = 0;
  1293.     out_count = 0;
  1294.     clear_flg = 0;
  1295.     in_count = 1;
  1296.     maxcode = MAXCODE(n_bits = g_init_bits);
  1297.  
  1298.     ClearCode = (1 << (init_bits - 1));
  1299.     EOFCode = ClearCode + 1;
  1300.     free_ent = ClearCode + 2;
  1301.  
  1302.     char_init();
  1303.  
  1304.     ent = GIFNextPixel( im );
  1305.  
  1306.     hshift = 0;
  1307.     for ( fcode = (long) hsize;  fcode < 65536L; fcode *= 2L )
  1308.         ++hshift;
  1309.     hshift = 8 - hshift;                /* set hash code range bound */
  1310.  
  1311.     hsize_reg = hsize;
  1312.     cl_hash( (count_int) hsize_reg);            /* clear hash table */
  1313.  
  1314.     output( (code_int)ClearCode );
  1315.  
  1316. #ifdef SIGNED_COMPARE_SLOW
  1317.     while ( (c = GIFNextPixel( im )) != (unsigned) EOF ) {
  1318. #else /*SIGNED_COMPARE_SLOW*/
  1319.     while ( (c = GIFNextPixel( im )) != EOF ) {  /* } */
  1320. #endif /*SIGNED_COMPARE_SLOW*/
  1321.  
  1322.         ++in_count;
  1323.  
  1324.         fcode = (long) (((long) c << maxbits) + ent);
  1325.         i = (((code_int)c << hshift) ^ ent);    /* xor hashing */
  1326.  
  1327.         if ( HashTabOf (i) == fcode ) {
  1328.             ent = CodeTabOf (i);
  1329.             continue;
  1330.         } else if ( (long)HashTabOf (i) < 0 )      /* empty slot */
  1331.             goto nomatch;
  1332.         disp = hsize_reg - i;           /* secondary hash (after G. Knott) */
  1333.         if ( i == 0 )
  1334.             disp = 1;
  1335. probe:
  1336.         if ( (i -= disp) < 0 )
  1337.             i += hsize_reg;
  1338.  
  1339.         if ( HashTabOf (i) == fcode ) {
  1340.             ent = CodeTabOf (i);
  1341.             continue;
  1342.         }
  1343.         if ( (long)HashTabOf (i) > 0 )
  1344.             goto probe;
  1345. nomatch:
  1346.         output ( (code_int) ent );
  1347.         ++out_count;
  1348.         ent = c;
  1349. #ifdef SIGNED_COMPARE_SLOW
  1350.         if ( (unsigned) free_ent < (unsigned) maxmaxcode) {
  1351. #else /*SIGNED_COMPARE_SLOW*/
  1352.         if ( free_ent < maxmaxcode ) {  /* } */
  1353. #endif /*SIGNED_COMPARE_SLOW*/
  1354.             CodeTabOf (i) = free_ent++; /* code -> hashtable */
  1355.             HashTabOf (i) = fcode;
  1356.         } else
  1357.                 cl_block();
  1358.     }
  1359.     /*
  1360.      * Put out the final code.
  1361.      */
  1362.     output( (code_int)ent );
  1363.     ++out_count;
  1364.     output( (code_int) EOFCode );
  1365. }
  1366.  
  1367. /*****************************************************************
  1368.  * TAG( output )
  1369.  *
  1370.  * Output the given code.
  1371.  * Inputs:
  1372.  *      code:   A n_bits-bit integer.  If == -1, then EOF.  This assumes
  1373.  *              that n_bits =< (long)wordsize - 1.
  1374.  * Outputs:
  1375.  *      Outputs code to the file.
  1376.  * Assumptions:
  1377.  *      Chars are 8 bits long.
  1378.  * Algorithm:
  1379.  *      Maintain a GIFBITS character long buffer (so that 8 codes will
  1380.  * fit in it exactly).  Use the VAX insv instruction to insert each
  1381.  * code in turn.  When the buffer fills up empty it and start over.
  1382.  */
  1383.  
  1384. static unsigned long cur_accum = 0;
  1385. static int cur_bits = 0;
  1386.  
  1387. static unsigned long masks[] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F,
  1388.                                   0x001F, 0x003F, 0x007F, 0x00FF,
  1389.                                   0x01FF, 0x03FF, 0x07FF, 0x0FFF,
  1390.                                   0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF };
  1391.  
  1392. static void
  1393. output( code )
  1394. code_int  code;
  1395. {
  1396.     cur_accum &= masks[ cur_bits ];
  1397.  
  1398.     if( cur_bits > 0 )
  1399.         cur_accum |= ((long)code << cur_bits);
  1400.     else
  1401.         cur_accum = code;
  1402.  
  1403.     cur_bits += n_bits;
  1404.  
  1405.     while( cur_bits >= 8 ) {
  1406.         char_out( (unsigned int)(cur_accum & 0xff) );
  1407.         cur_accum >>= 8;
  1408.         cur_bits -= 8;
  1409.     }
  1410.  
  1411.     /*
  1412.      * If the next entry is going to be too big for the code size,
  1413.      * then increase it, if possible.
  1414.      */
  1415.    if ( free_ent > maxcode || clear_flg ) {
  1416.  
  1417.             if( clear_flg ) {
  1418.  
  1419.                 maxcode = MAXCODE (n_bits = g_init_bits);
  1420.                 clear_flg = 0;
  1421.  
  1422.             } else {
  1423.  
  1424.                 ++n_bits;
  1425.                 if ( n_bits == maxbits )
  1426.                     maxcode = maxmaxcode;
  1427.                 else
  1428.                     maxcode = MAXCODE(n_bits);
  1429.             }
  1430.         }
  1431.  
  1432.     if( code == EOFCode ) {
  1433.         /*
  1434.          * At EOF, write the rest of the buffer.
  1435.          */
  1436.         while( cur_bits > 0 ) {
  1437.                 char_out( (unsigned int)(cur_accum & 0xff) );
  1438.                 cur_accum >>= 8;
  1439.                 cur_bits -= 8;
  1440.         }
  1441.  
  1442.         flush_char();
  1443.  
  1444.         fflush( g_outfile );
  1445.  
  1446.         if( ferror( g_outfile ) )
  1447.         exit(1);
  1448.     }
  1449. }
  1450.  
  1451. /*
  1452.  * Clear out the hash table
  1453.  */
  1454. static void
  1455. cl_block ()             /* table clear for block compress */
  1456. {
  1457.  
  1458.         cl_hash ( (count_int) hsize );
  1459.         free_ent = ClearCode + 2;
  1460.         clear_flg = 1;
  1461.  
  1462.         output( (code_int)ClearCode );
  1463. }
  1464.  
  1465. static void
  1466. cl_hash(hsize)          /* reset code table */
  1467. register count_int hsize;
  1468. {
  1469.  
  1470.         register count_int *htab_p = htab+hsize;
  1471.  
  1472.         register long i;
  1473.         register long m1 = -1;
  1474.  
  1475.         i = hsize - 16;
  1476.         do {                            /* might use Sys V memset(3) here */
  1477.                 *(htab_p-16) = m1;
  1478.                 *(htab_p-15) = m1;
  1479.                 *(htab_p-14) = m1;
  1480.                 *(htab_p-13) = m1;
  1481.                 *(htab_p-12) = m1;
  1482.                 *(htab_p-11) = m1;
  1483.                 *(htab_p-10) = m1;
  1484.                 *(htab_p-9) = m1;
  1485.                 *(htab_p-8) = m1;
  1486.                 *(htab_p-7) = m1;
  1487.                 *(htab_p-6) = m1;
  1488.                 *(htab_p-5) = m1;
  1489.                 *(htab_p-4) = m1;
  1490.                 *(htab_p-3) = m1;
  1491.                 *(htab_p-2) = m1;
  1492.                 *(htab_p-1) = m1;
  1493.                 htab_p -= 16;
  1494.         } while ((i -= 16) >= 0);
  1495.  
  1496.         for ( i += 16; i > 0; --i )
  1497.                 *--htab_p = m1;
  1498. }
  1499.  
  1500. /******************************************************************************
  1501.  *
  1502.  * GIF Specific routines
  1503.  *
  1504.  ******************************************************************************/
  1505.  
  1506. /*
  1507.  * Number of characters so far in this 'packet'
  1508.  */
  1509. static int a_count;
  1510.  
  1511. /*
  1512.  * Set up the 'byte output' routine
  1513.  */
  1514. static void
  1515. char_init()
  1516. {
  1517.         a_count = 0;
  1518. }
  1519.  
  1520. /*
  1521.  * Define the storage for the packet accumulator
  1522.  */
  1523. static char accum[ 256 ];
  1524.  
  1525. /*
  1526.  * Add a character to the end of the current packet, and if it is 254
  1527.  * characters, flush the packet to disk.
  1528.  */
  1529. static void
  1530. char_out( c )
  1531. int c;
  1532. {
  1533.         accum[ a_count++ ] = c;
  1534.         if( a_count >= 254 )
  1535.                 flush_char();
  1536. }
  1537.  
  1538. /*
  1539.  * Flush the packet to disk, and reset the accumulator
  1540.  */
  1541. static void
  1542. flush_char()
  1543. {
  1544.         if( a_count > 0 ) {
  1545.                 fputc( a_count, g_outfile );
  1546.                 fwrite( accum, 1, a_count, g_outfile );
  1547.                 a_count = 0;
  1548.         }
  1549. }
  1550.  
  1551. static void init_statics() {
  1552.     /* Some of these are properly initialized later. What I'm doing
  1553.         here is making sure code that depends on C's initialization
  1554.         of statics doesn't break when the code gets called more
  1555.         than once. */
  1556.     Width = 0;
  1557.     Height = 0;
  1558.     curx = 0;
  1559.     cury = 0;
  1560.     CountDown = 0;
  1561.     Pass = 0;
  1562.     Interlace = 0;
  1563.     a_count = 0;
  1564.     cur_accum = 0;
  1565.     cur_bits = 0;
  1566.     g_init_bits = 0;
  1567.     g_outfile = 0;
  1568.     ClearCode = 0;
  1569.     EOFCode = 0;
  1570.     free_ent = 0;
  1571.     clear_flg = 0;
  1572.     offset = 0;
  1573.     in_count = 1;
  1574.     out_count = 0;    
  1575.     hsize = HSIZE;
  1576.     n_bits = 0;
  1577.     maxbits = GIFBITS;
  1578.     maxcode = 0;
  1579.     maxmaxcode = (code_int)1 << GIFBITS;
  1580. }
  1581.  
  1582.  
  1583. /* +-------------------------------------------------------------------+ */
  1584. /* | Copyright 1990, 1991, 1993, David Koblas.  (koblas@netcom.com)    | */
  1585. /* |   Permission to use, copy, modify, and distribute this software   | */
  1586. /* |   and its documentation for any purpose and without fee is hereby | */
  1587. /* |   granted, provided that the above copyright notice appear in all | */
  1588. /* |   copies and that both that copyright notice and this permission  | */
  1589. /* |   notice appear in supporting documentation.  This software is    | */
  1590. /* |   provided "as is" without express or implied warranty.           | */
  1591. /* +-------------------------------------------------------------------+ */
  1592.  
  1593.  
  1594. #define        MAXCOLORMAPSIZE         256
  1595.  
  1596. #define        TRUE    1
  1597. #define        FALSE   0
  1598.  
  1599. #define CM_RED         0
  1600. #define CM_GREEN       1
  1601. #define CM_BLUE                2
  1602.  
  1603. #define        MAX_LWZ_BITS            12
  1604.  
  1605. #define INTERLACE              0x40
  1606. #define LOCALCOLORMAP  0x80
  1607. #define BitSet(byte, bit)      (((byte) & (bit)) == (bit))
  1608.  
  1609. #define        ReadOK(file,buffer,len) (fread(buffer, len, 1, file) != 0)
  1610.  
  1611. #define LM_to_uint(a,b)                        (((b)<<8)|(a))
  1612.  
  1613. static struct {
  1614.        unsigned int    Width;
  1615.        unsigned int    Height;
  1616.        unsigned char   ColorMap[3][MAXCOLORMAPSIZE];
  1617.        unsigned int    BitPixel;
  1618.        unsigned int    ColorResolution;
  1619.        unsigned int    Background;
  1620.        unsigned int    AspectRatio;
  1621. } GifScreen;
  1622.  
  1623. static struct {
  1624.        int     transparent;
  1625.        int     delayTime;
  1626.        int     inputFlag;
  1627.        int     disposal;
  1628. } Gif89 = { -1, -1, -1, 0 };
  1629.  
  1630. static int ReadColorMap ( /* FILE *fd, int number, gdImagePtr im, int *flag */);
  1631. static int DoExtension (/* FILE *fd, int label */);
  1632. static int GetDataBlock (/* FILE *fd, unsigned char  *buf */);
  1633. static int GetCode (/* FILE *fd, int code_size, int flag */);
  1634. static int LWZReadByte (/* FILE *fd, int flag, int input_code_size */);
  1635. static void ReadImage (/* gdImagePtr im, FILE *fd, int len, int height, int interlace, int ignore */);
  1636.  
  1637. int ZeroDataBlock;
  1638.  
  1639. gdImagePtr
  1640. gdImageCreateFromGif(fd)
  1641. FILE   *fd;
  1642. {
  1643.        int imageNumber;
  1644.        int BitPixel;
  1645.        int ColorResolution;
  1646.        int Background;
  1647.        int AspectRatio;
  1648.        int Transparent = (-1);
  1649.        unsigned char   buf[16];
  1650.        unsigned char   c;
  1651.        unsigned char   ColorMap[3][MAXCOLORMAPSIZE];
  1652.        unsigned char   localColorMap[3][MAXCOLORMAPSIZE];
  1653.        int             imw, imh;
  1654.        int             useGlobalColormap;
  1655.        int             bitPixel;
  1656.        int             imageCount = 0;
  1657.        char            version[4];
  1658.        gdImagePtr im;
  1659.        ZeroDataBlock = FALSE;
  1660.  
  1661.        imageNumber = 1;
  1662.        if (! ReadOK(fd,buf,6)) {
  1663.         return 0;
  1664.     }
  1665.        if (strncmp((char *)buf,"GIF",3) != 0) {
  1666.         return 0;
  1667.     }
  1668.        strncpy(version, (char *)buf + 3, 3);
  1669.        version[3] = '\0';
  1670.  
  1671.        if ((strcmp(version, "87a") != 0) && (strcmp(version, "89a") != 0)) {
  1672.         return 0;
  1673.     }
  1674.        if (! ReadOK(fd,buf,7)) {
  1675.         return 0;
  1676.     }
  1677.        BitPixel        = 2<<(buf[4]&0x07);
  1678.        ColorResolution = (((buf[4]&0x70)>>3)+1);
  1679.        Background      = buf[5];
  1680.        AspectRatio     = buf[6];
  1681.  
  1682.        if (BitSet(buf[4], LOCALCOLORMAP)) {    /* Global Colormap */
  1683.                if (ReadColorMap(fd, BitPixel, ColorMap)) {
  1684.             return 0;
  1685.         }
  1686.        }
  1687.        for (;;) {
  1688.                if (! ReadOK(fd,&c,1)) {
  1689.                        return 0;
  1690.                }
  1691.                if (c == ';') {         /* GIF terminator */
  1692.                        int i;
  1693.                        if (imageCount < imageNumber) {
  1694.                                return 0;
  1695.                        }
  1696.                /* Check for open colors at the end, so
  1697.                           we can reduce colorsTotal and ultimately
  1698.                           BitsPerPixel */
  1699.                        for (i=((im->colorsTotal-1)); (i>=0); i--) {
  1700.                                if (im->open[i]) {
  1701.                                        im->colorsTotal--;
  1702.                                } else {
  1703.                                        break;
  1704.                                }
  1705.                        } 
  1706.                        return im;
  1707.                }
  1708.  
  1709.                if (c == '!') {         /* Extension */
  1710.                        if (! ReadOK(fd,&c,1)) {
  1711.                                return 0;
  1712.                        }
  1713.                        DoExtension(fd, c, &Transparent);
  1714.                        continue;
  1715.                }
  1716.  
  1717.                if (c != ',') {         /* Not a valid start character */
  1718.                        continue;
  1719.                }
  1720.  
  1721.                ++imageCount;
  1722.  
  1723.                if (! ReadOK(fd,buf,9)) {
  1724.                    return 0;
  1725.                }
  1726.  
  1727.                useGlobalColormap = ! BitSet(buf[8], LOCALCOLORMAP);
  1728.  
  1729.                bitPixel = 1<<((buf[8]&0x07)+1);
  1730.  
  1731.                imw = LM_to_uint(buf[4],buf[5]);
  1732.                imh = LM_to_uint(buf[6],buf[7]);
  1733.            if (!(im = gdImageCreate(imw, imh))) {
  1734.              return 0;
  1735.            }
  1736.                im->interlace = BitSet(buf[8], INTERLACE);
  1737.                if (! useGlobalColormap) {
  1738.                        if (ReadColorMap(fd, bitPixel, localColorMap)) { 
  1739.                                  return 0;
  1740.                        }
  1741.                        ReadImage(im, fd, imw, imh, localColorMap, 
  1742.                                  BitSet(buf[8], INTERLACE), 
  1743.                                  imageCount != imageNumber);
  1744.                } else {
  1745.                        ReadImage(im, fd, imw, imh,
  1746.                                  ColorMap, 
  1747.                                  BitSet(buf[8], INTERLACE), 
  1748.                                  imageCount != imageNumber);
  1749.                }
  1750.                if (Transparent != (-1)) {
  1751.                        gdImageColorTransparent(im, Transparent);
  1752.                }       
  1753.        }
  1754. }
  1755.  
  1756. static int
  1757. ReadColorMap(fd,number,buffer)
  1758. FILE           *fd;
  1759. int            number;
  1760. unsigned char  buffer[3][MAXCOLORMAPSIZE];
  1761. {
  1762.        int             i;
  1763.        unsigned char   rgb[3];
  1764.  
  1765.  
  1766.        for (i = 0; i < number; ++i) {
  1767.                if (! ReadOK(fd, rgb, sizeof(rgb))) {
  1768.                        return TRUE;
  1769.                }
  1770.                buffer[CM_RED][i] = rgb[0] ;
  1771.                buffer[CM_GREEN][i] = rgb[1] ;
  1772.                buffer[CM_BLUE][i] = rgb[2] ;
  1773.        }
  1774.  
  1775.  
  1776.        return FALSE;
  1777. }
  1778.  
  1779. static int
  1780. DoExtension(fd, label, Transparent)
  1781. FILE   *fd;
  1782. int    label;
  1783. int    *Transparent;
  1784. {
  1785.        static char     buf[256];
  1786.  
  1787.        switch (label) {
  1788.        case 0xf9:              /* Graphic Control Extension */
  1789.                (void) GetDataBlock(fd, (unsigned char*) buf);
  1790.                Gif89.disposal    = (buf[0] >> 2) & 0x7;
  1791.                Gif89.inputFlag   = (buf[0] >> 1) & 0x1;
  1792.                Gif89.delayTime   = LM_to_uint(buf[1],buf[2]);
  1793.                if ((buf[0] & 0x1) != 0)
  1794.                        *Transparent = buf[3];
  1795.  
  1796.                while (GetDataBlock(fd, (unsigned char*) buf) != 0)
  1797.                        ;
  1798.                return FALSE;
  1799.        default:
  1800.                break;
  1801.        }
  1802.        while (GetDataBlock(fd, (unsigned char*) buf) != 0)
  1803.                ;
  1804.  
  1805.        return FALSE;
  1806. }
  1807.  
  1808. static int
  1809. GetDataBlock(fd, buf)
  1810. FILE           *fd;
  1811. unsigned char  *buf;
  1812. {
  1813.        unsigned char   count;
  1814.  
  1815.        if (! ReadOK(fd,&count,1)) {
  1816.                return -1;
  1817.        }
  1818.  
  1819.        ZeroDataBlock = count == 0;
  1820.  
  1821.        if ((count != 0) && (! ReadOK(fd, buf, count))) {
  1822.                return -1;
  1823.        }
  1824.  
  1825.        return count;
  1826. }
  1827.  
  1828. static int
  1829. GetCode(fd, code_size, flag)
  1830. FILE   *fd;
  1831. int    code_size;
  1832. int    flag;
  1833. {
  1834.        static unsigned char    buf[280];
  1835.        static int              curbit, lastbit, done, last_byte;
  1836.        int                     i, j, ret;
  1837.        unsigned char           count;
  1838.  
  1839.        if (flag) {
  1840.                curbit = 0;
  1841.                lastbit = 0;
  1842.                done = FALSE;
  1843.                return 0;
  1844.        }
  1845.  
  1846.        if ( (curbit+code_size) >= lastbit) {
  1847.                if (done) {
  1848.                        if (curbit >= lastbit) {
  1849.                                 /* Oh well */
  1850.                        }                        
  1851.                        return -1;
  1852.                }
  1853.                buf[0] = buf[last_byte-2];
  1854.                buf[1] = buf[last_byte-1];
  1855.  
  1856.                if ((count = GetDataBlock(fd, &buf[2])) == 0)
  1857.                        done = TRUE;
  1858.  
  1859.                last_byte = 2 + count;
  1860.                curbit = (curbit - lastbit) + 16;
  1861.                lastbit = (2+count)*8 ;
  1862.        }
  1863.  
  1864.        ret = 0;
  1865.        for (i = curbit, j = 0; j < code_size; ++i, ++j)
  1866.                ret |= ((buf[ i / 8 ] & (1 << (i % 8))) != 0) << j;
  1867.  
  1868.        curbit += code_size;
  1869.  
  1870.        return ret;
  1871. }
  1872.  
  1873. static int
  1874. LWZReadByte(fd, flag, input_code_size)
  1875. FILE   *fd;
  1876. int    flag;
  1877. int    input_code_size;
  1878. {
  1879.        static int      fresh = FALSE;
  1880.        int             code, incode;
  1881.        static int      code_size, set_code_size;
  1882.        static int      max_code, max_code_size;
  1883.        static int      firstcode, oldcode;
  1884.        static int      clear_code, end_code;
  1885.        static int      table[2][(1<< MAX_LWZ_BITS)];
  1886.        static int      stack[(1<<(MAX_LWZ_BITS))*2], *sp;
  1887.        register int    i;
  1888.  
  1889.        if (flag) {
  1890.                set_code_size = input_code_size;
  1891.                code_size = set_code_size+1;
  1892.                clear_code = 1 << set_code_size ;
  1893.                end_code = clear_code + 1;
  1894.                max_code_size = 2*clear_code;
  1895.                max_code = clear_code+2;
  1896.  
  1897.                GetCode(fd, 0, TRUE);
  1898.                
  1899.                fresh = TRUE;
  1900.  
  1901.                for (i = 0; i < clear_code; ++i) {
  1902.                        table[0][i] = 0;
  1903.                        table[1][i] = i;
  1904.                }
  1905.                for (; i < (1<<MAX_LWZ_BITS); ++i)
  1906.                        table[0][i] = table[1][0] = 0;
  1907.  
  1908.                sp = stack;
  1909.  
  1910.                return 0;
  1911.        } else if (fresh) {
  1912.                fresh = FALSE;
  1913.                do {
  1914.                        firstcode = oldcode =
  1915.                                GetCode(fd, code_size, FALSE);
  1916.                } while (firstcode == clear_code);
  1917.                return firstcode;
  1918.        }
  1919.  
  1920.        if (sp > stack)
  1921.                return *--sp;
  1922.  
  1923.        while ((code = GetCode(fd, code_size, FALSE)) >= 0) {
  1924.                if (code == clear_code) {
  1925.                        for (i = 0; i < clear_code; ++i) {
  1926.                                table[0][i] = 0;
  1927.                                table[1][i] = i;
  1928.                        }
  1929.                        for (; i < (1<<MAX_LWZ_BITS); ++i)
  1930.                                table[0][i] = table[1][i] = 0;
  1931.                        code_size = set_code_size+1;
  1932.                        max_code_size = 2*clear_code;
  1933.                        max_code = clear_code+2;
  1934.                        sp = stack;
  1935.                        firstcode = oldcode =
  1936.                                        GetCode(fd, code_size, FALSE);
  1937.                        return firstcode;
  1938.                } else if (code == end_code) {
  1939.                        int             count;
  1940.                        unsigned char   buf[260];
  1941.  
  1942.                        if (ZeroDataBlock)
  1943.                                return -2;
  1944.  
  1945.                        while ((count = GetDataBlock(fd, buf)) > 0)
  1946.                                ;
  1947.  
  1948.                        if (count != 0)
  1949.                        return -2;
  1950.                }
  1951.  
  1952.                incode = code;
  1953.  
  1954.                if (code >= max_code) {
  1955.                        *sp++ = firstcode;
  1956.                        code = oldcode;
  1957.                }
  1958.  
  1959.                while (code >= clear_code) {
  1960.                        *sp++ = table[1][code];
  1961.                        if (code == table[0][code]) {
  1962.                                /* Oh well */
  1963.                        }
  1964.                        code = table[0][code];
  1965.                }
  1966.  
  1967.                *sp++ = firstcode = table[1][code];
  1968.  
  1969.                if ((code = max_code) <(1<<MAX_LWZ_BITS)) {
  1970.                        table[0][code] = oldcode;
  1971.                        table[1][code] = firstcode;
  1972.                        ++max_code;
  1973.                        if ((max_code >= max_code_size) &&
  1974.                                (max_code_size < (1<<MAX_LWZ_BITS))) {
  1975.                                max_code_size *= 2;
  1976.                                ++code_size;
  1977.                        }
  1978.                }
  1979.  
  1980.                oldcode = incode;
  1981.  
  1982.                if (sp > stack)
  1983.                        return *--sp;
  1984.        }
  1985.        return code;
  1986. }
  1987.  
  1988. static void
  1989. ReadImage(im, fd, len, height, cmap, interlace, ignore)
  1990. gdImagePtr im;
  1991. FILE   *fd;
  1992. int    len, height;
  1993. unsigned char  cmap[3][MAXCOLORMAPSIZE];
  1994. int    interlace, ignore;
  1995. {
  1996.        unsigned char   c;      
  1997.        int             v;
  1998.        int             xpos = 0, ypos = 0, pass = 0;
  1999.        int i;
  2000.        /* Stash the color map into the image */
  2001.        for (i=0; (i<gdMaxColors); i++) {
  2002.                im->red[i] = cmap[CM_RED][i];    
  2003.                im->green[i] = cmap[CM_GREEN][i];    
  2004.                im->blue[i] = cmap[CM_BLUE][i];    
  2005.                im->open[i] = 1;
  2006.        }
  2007.        /* Many (perhaps most) of these colors will remain marked open. */
  2008.        im->colorsTotal = gdMaxColors;
  2009.        /*
  2010.        **  Initialize the Compression routines
  2011.        */
  2012.        if (! ReadOK(fd,&c,1)) {
  2013.                return; 
  2014.        }
  2015.        if (LWZReadByte(fd, TRUE, c) < 0) {
  2016.                return;
  2017.        }
  2018.  
  2019.        /*
  2020.        **  If this is an "uninteresting picture" ignore it.
  2021.        */
  2022.        if (ignore) {
  2023.                while (LWZReadByte(fd, FALSE, c) >= 0)
  2024.                        ;
  2025.                return;
  2026.        }
  2027.  
  2028.        while ((v = LWZReadByte(fd,FALSE,c)) >= 0 ) {
  2029.                /* This how we recognize which colors are actually used. */
  2030.                if (im->open[v]) {
  2031.                        im->open[v] = 0;
  2032.                }
  2033.                gdImageSetPixel(im, xpos, ypos, v);
  2034.                ++xpos;
  2035.                if (xpos == len) {
  2036.                        xpos = 0;
  2037.                        if (interlace) {
  2038.                                switch (pass) {
  2039.                                case 0:
  2040.                                case 1:
  2041.                                        ypos += 8; break;
  2042.                                case 2:
  2043.                                        ypos += 4; break;
  2044.                                case 3:
  2045.                                        ypos += 2; break;
  2046.                                }
  2047.  
  2048.                                if (ypos >= height) {
  2049.                                        ++pass;
  2050.                                        switch (pass) {
  2051.                                        case 1:
  2052.                                                ypos = 4; break;
  2053.                                        case 2:
  2054.                                                ypos = 2; break;
  2055.                                        case 3:
  2056.                                                ypos = 1; break;
  2057.                                        default:
  2058.                                                goto fini;
  2059.                                        }
  2060.                                }
  2061.                        } else {
  2062.                                ++ypos;
  2063.                        }
  2064.                }
  2065.                if (ypos >= height)
  2066.                        break;
  2067.        }
  2068.  
  2069. fini:
  2070.        if (LWZReadByte(fd,FALSE,c)>=0) {
  2071.                /* Ignore extra */
  2072.        }
  2073. }
  2074.  
  2075. void gdImageRectangle(im, x1, y1, x2, y2, color)
  2076.     gdImagePtr im;
  2077.     int x1; 
  2078.     int y1; 
  2079.     int x2; 
  2080.     int y2; 
  2081. {
  2082.     gdImageLine(im, x1, y1, x2, y1, color);        
  2083.     gdImageLine(im, x1, y2, x2, y2, color);        
  2084.     gdImageLine(im, x1, y1, x1, y2, color);
  2085.     gdImageLine(im, x2, y1, x2, y2, color);
  2086. }
  2087.  
  2088. void gdImageFilledRectangle(im, x1, y1, x2, y2, color)
  2089.     gdImagePtr im;
  2090.     int x1; 
  2091.     int y1; 
  2092.     int x2; 
  2093.     int y2; 
  2094.     int color;
  2095. {
  2096.     int x, y;
  2097.     for (y=y1; (y<=y2); y++) {
  2098.         for (x=x1; (x<=x2); x++) {
  2099.             gdImageSetPixel(im, x, y, color);
  2100.         }
  2101.     }
  2102. }
  2103.  
  2104. void gdImageCopy(dst, src, dstX, dstY, srcX, srcY, w, h)
  2105.     gdImagePtr dst;
  2106.     gdImagePtr src;
  2107.         int dstX; 
  2108.     int dstY; 
  2109.     int srcX; 
  2110.     int srcY; 
  2111.     int w; 
  2112.     int h;
  2113. {
  2114.     int c;
  2115.     int x, y;
  2116.     int tox, toy;
  2117.     int i;
  2118.     int colorMap[gdMaxColors];
  2119.     for (i=0; (i<gdMaxColors); i++) {
  2120.         colorMap[i] = (-1);
  2121.     }
  2122.     toy = dstY;
  2123.     for (y=srcY; (y < (srcY + h)); y++) {
  2124.         tox = dstX;
  2125.         for (x=srcX; (x < (srcX + w)); x++) {
  2126.             int nc;
  2127.             c = gdImageGetPixel(src, x, y);
  2128.             /* Have we established a mapping for this color? */
  2129.             if (colorMap[c] == (-1)) {
  2130.                 /* If it's the same image, mapping is trivial */
  2131.                 if (dst == src) {
  2132.                     nc = c;
  2133.                 } else { 
  2134.                     /* First look for an exact match */
  2135.                     nc = gdImageColorExact(dst,
  2136.                         src->red[c], src->green[c],
  2137.                         src->blue[c]);
  2138.                 }    
  2139.                 if (nc == (-1)) {
  2140.                     /* No, so try to allocate it */
  2141.                     nc = gdImageColorAllocate(dst,
  2142.                         src->red[c], src->green[c],
  2143.                         src->blue[c]);
  2144.                     /* If we're out of colors, go for the
  2145.                         closest color */
  2146.                     if (nc == (-1)) {
  2147.                         nc = gdImageColorClosest(dst,
  2148.                             src->red[c], src->green[c],
  2149.                             src->blue[c]);
  2150.                     }
  2151.                 }
  2152.                 colorMap[c] = nc;
  2153.             }
  2154.             gdImageSetPixel(dst, tox, toy, colorMap[c]);
  2155.             tox++;
  2156.         }
  2157.         toy++;
  2158.     }
  2159. }            
  2160.  
  2161. void gdImageCopyResized(dst, src, dstX, dstY, srcX, srcY,
  2162.     dstW, dstH, srcW, srcH)
  2163.     gdImagePtr dst;
  2164.     gdImagePtr src;
  2165.         int dstX; 
  2166.     int dstY; 
  2167.     int srcX; 
  2168.     int srcY; 
  2169.         int dstW; 
  2170.     int dstH; 
  2171.     int srcW; 
  2172.     int srcH; 
  2173. {
  2174.     int c;
  2175.     int x, y;
  2176.     int tox, toy;
  2177.     int ydest;
  2178.     int i;
  2179.     int colorMap[gdMaxColors];
  2180.     /* Stretch vectors */
  2181.     int *stx;
  2182.     int *sty;
  2183.     /* We only need to use floating point to determine the correct
  2184.         stretch vector for one line's worth. */
  2185.     double accum;
  2186.     stx = (int *) malloc(sizeof(int) * srcW);
  2187.     sty = (int *) malloc(sizeof(int) * srcH);
  2188.     accum = 0;
  2189.     for (i=0; (i < srcW); i++) {
  2190.         int got;
  2191.         accum += (double)dstW/(double)srcW;
  2192.         got = floor(accum);
  2193.         stx[i] = got;
  2194.         accum -= got;
  2195.     }
  2196.     accum = 0;
  2197.     for (i=0; (i < srcH); i++) {
  2198.         int got;
  2199.         accum += (double)dstH/(double)srcH;
  2200.         got = floor(accum);
  2201.         sty[i] = got;
  2202.         accum -= got;
  2203.     }
  2204.     for (i=0; (i<gdMaxColors); i++) {
  2205.         colorMap[i] = (-1);
  2206.     }
  2207.     toy = dstY;
  2208.     for (y=srcY; (y < (srcY + srcH)); y++) {
  2209.         for (ydest=0; (ydest < sty[y-srcY]); ydest++) {
  2210.             tox = dstX;
  2211.             for (x=srcX; (x < (srcX + srcW)); x++) {
  2212.                 int nc;
  2213.                 if (!stx[x - srcX]) {
  2214.                     continue;
  2215.                 }
  2216.                 c = gdImageGetPixel(src, x, y);
  2217.                 /* Have we established a mapping for this color? */
  2218.                 if (colorMap[c] == (-1)) {
  2219.                     /* If it's the same image, mapping is trivial */
  2220.                     if (dst == src) {
  2221.                         nc = c;
  2222.                     } else { 
  2223.                         /* First look for an exact match */
  2224.                         nc = gdImageColorExact(dst,
  2225.                             src->red[c], src->green[c],
  2226.                             src->blue[c]);
  2227.                     }    
  2228.                     if (nc == (-1)) {
  2229.                         /* No, so try to allocate it */
  2230.                         nc = gdImageColorAllocate(dst,
  2231.                             src->red[c], src->green[c],
  2232.                             src->blue[c]);
  2233.                         /* If we're out of colors, go for the
  2234.                             closest color */
  2235.                         if (nc == (-1)) {
  2236.                             nc = gdImageColorClosest(dst,
  2237.                                 src->red[c], src->green[c],
  2238.                                 src->blue[c]);
  2239.                         }
  2240.                     }
  2241.                     colorMap[c] = nc;
  2242.                 }
  2243.                 for (i=0; (i < stx[x - srcX]); i++) {
  2244.                     gdImageSetPixel(dst, tox, toy, colorMap[c]);
  2245.                     tox++;
  2246.                 }
  2247.             }
  2248.             toy++;
  2249.         }
  2250.     }
  2251.     free(stx);
  2252.     free(sty);
  2253. }
  2254.  
  2255. int gdGetWord(result, in)
  2256.     int *result;
  2257.     FILE *in;
  2258. {
  2259.     int r;
  2260.     r = getc(in);
  2261.     if (r == EOF) {
  2262.         return 0;
  2263.     }
  2264.     *result = r << 8;
  2265.     r = getc(in);    
  2266.     if (r == EOF) {
  2267.         return 0;
  2268.     }
  2269.     *result += r;
  2270.     return 1;
  2271. }
  2272.  
  2273. void gdPutWord(w, out)
  2274.     int w;
  2275.     FILE *out;
  2276. {
  2277.     putc((unsigned char)(w >> 8), out);
  2278.     putc((unsigned char)(w & 0xFF), out);
  2279. }
  2280.  
  2281. int gdGetByte(result, in)
  2282.     int *result;
  2283.     FILE *in;
  2284. {
  2285.     int r;
  2286.     r = getc(in);
  2287.     if (r == EOF) {
  2288.         return 0;
  2289.     }
  2290.     *result = r;
  2291.     return 1;
  2292. }
  2293.  
  2294. gdImagePtr gdImageCreateFromGd(in) 
  2295.     FILE *in; 
  2296. {
  2297.     int sx, sy;
  2298.     int x, y;
  2299.     int i;
  2300.     gdImagePtr im;
  2301.     if (!gdGetWord(&sx, in)) {
  2302.         goto fail1;
  2303.     }
  2304.     if (!gdGetWord(&sy, in)) {
  2305.         goto fail1;
  2306.     }
  2307.     im = gdImageCreate(sx, sy);
  2308.     if (!gdGetByte(&im->colorsTotal, in)) {
  2309.         goto fail2;
  2310.     }
  2311.     if (!gdGetWord(&im->transparent, in)) {
  2312.         goto fail2;
  2313.     }
  2314.     if (im->transparent == 257) {
  2315.         im->transparent = (-1);
  2316.     }
  2317.     for (i=0; (i<gdMaxColors); i++) {
  2318.         if (!gdGetByte(&im->red[i], in)) {
  2319.             goto fail2;
  2320.         }
  2321.         if (!gdGetByte(&im->green[i], in)) {
  2322.             goto fail2;
  2323.         }
  2324.         if (!gdGetByte(&im->blue[i], in)) {
  2325.             goto fail2;
  2326.         }
  2327.     }    
  2328.     for (y=0; (y<sy); y++) {
  2329.         for (x=0; (x<sx); x++) {    
  2330.             int ch;
  2331.             ch = getc(in);
  2332.             if (ch == EOF) {
  2333.                 gdImageDestroy(im);
  2334.                 return 0;
  2335.             }
  2336.             im->pixels[x][y] = ch;
  2337.         }
  2338.     }
  2339.     return im;
  2340. fail2:
  2341.     gdImageDestroy(im);
  2342. fail1:
  2343.     return 0;
  2344. }
  2345.     
  2346. void gdImageGd(im, out)
  2347.     gdImagePtr im; 
  2348.     FILE *out; 
  2349. {
  2350.     int x, y;
  2351.     int i;
  2352.     int trans;
  2353.     gdPutWord(im->sx, out);
  2354.     gdPutWord(im->sy, out);
  2355.     putc((unsigned char)im->colorsTotal, out);
  2356.     trans = im->transparent;
  2357.     if (trans == (-1)) {
  2358.         trans = 257;
  2359.     }    
  2360.     gdPutWord(trans, out);
  2361.     for (i=0; (i<gdMaxColors); i++) {
  2362.         putc((unsigned char)im->red[i], out);
  2363.         putc((unsigned char)im->green[i], out);    
  2364.         putc((unsigned char)im->blue[i], out);    
  2365.     }
  2366.     for (y=0; (y < im->sy); y++) {    
  2367.         for (x=0; (x < im->sx); x++) {    
  2368.             putc((unsigned char)im->pixels[x][y], out);
  2369.         }
  2370.     }
  2371. }
  2372.  
  2373. gdImagePtr
  2374. gdImageCreateFromXbm(fd)
  2375. FILE   *fd;
  2376. {
  2377.     gdImagePtr im;    
  2378.     int bit;
  2379.     int w, h;
  2380.     int bytes;
  2381.     int ch;
  2382.     int spaceat;
  2383.     int i, x, y;
  2384.     int bits;
  2385.     char *sp;
  2386.     char s[161];
  2387.     if (!fgets(s, 160, fd)) {
  2388.         return 0;
  2389.     }
  2390.     sp = &s[0];
  2391.     /* Skip #define */
  2392.     sp = strchr(sp, ' ');
  2393.     if (!sp) {
  2394.         return 0;
  2395.     }
  2396.     /* Skip width label */
  2397.     sp++;
  2398.     sp = strchr(sp, ' ');
  2399.     if (!sp) {
  2400.         return 0;
  2401.     }
  2402.     /* Get width */
  2403.     w = atoi(sp + 1);
  2404.     if (!w) {
  2405.         return 0;
  2406.     }
  2407.     if (!fgets(s, 160, fd)) {
  2408.         return 0;
  2409.     }
  2410.     sp = s;
  2411.     /* Skip #define */
  2412.     sp = strchr(sp, ' ');
  2413.     if (!sp) {
  2414.         return 0;
  2415.     }
  2416.     /* Skip height label */
  2417.     sp++;
  2418.     sp = strchr(sp, ' ');
  2419.     if (!sp) {
  2420.         return 0;
  2421.     }
  2422.     /* Get height */
  2423.     h = atoi(sp + 1);
  2424.     if (!h) {
  2425.         return 0;
  2426.     }
  2427.     /* Skip declaration line */
  2428.     if (!fgets(s, 160, fd)) {
  2429.         return 0;
  2430.     }
  2431.     bytes = (w * h / 8) + 1;
  2432.     im = gdImageCreate(w, h);
  2433.     gdImageColorAllocate(im, 255, 255, 255);
  2434.     gdImageColorAllocate(im, 0, 0, 0);
  2435.     x = 0;
  2436.     y = 0;
  2437.     for (i=0; (i < bytes); i++) {
  2438.         char h[3];
  2439.         int b;
  2440.         /* Skip spaces, commas, CRs, 0x */
  2441.         while(1) {
  2442.             ch = getc(fd);
  2443.             if (ch == EOF) {
  2444.                 goto fail;
  2445.             }
  2446.             if (ch == 'x') {
  2447.                 break;
  2448.             }    
  2449.         }
  2450.         /* Get hex value */
  2451.         ch = getc(fd);
  2452.         if (ch == EOF) {
  2453.             goto fail;
  2454.         }
  2455.         h[0] = ch;
  2456.         ch = getc(fd);
  2457.         if (ch == EOF) {
  2458.             goto fail;
  2459.         }
  2460.         h[1] = ch;
  2461.         h[2] = '\0';
  2462.         sscanf(h, "%x", &b);        
  2463.         for (bit = 1; (bit <= 128); (bit = bit << 1)) {
  2464.             gdImageSetPixel(im, x++, y, b & bit);    
  2465.             if (x == im->sx) {
  2466.                 x = 0;
  2467.                 y++;
  2468.                 if (y == im->sy) {
  2469.                     return im;
  2470.                 }
  2471.             }
  2472.         }
  2473.     }
  2474.     /* Shouldn't happen */
  2475.     fprintf(stderr, "Error: bug in gdImageCreateFromXbm!\n");
  2476.     return 0;
  2477. fail:
  2478.     gdImageDestroy(im);
  2479.     return 0;
  2480. }
  2481.  
  2482. void gdImagePolygon(im, p, n, c)
  2483.     gdImagePtr im;
  2484.     gdPointPtr p;
  2485.     int n;
  2486.     int c;
  2487. {
  2488.     int i;
  2489.     int lx, ly;
  2490.     if (!n) {
  2491.         return;
  2492.     }
  2493.     lx = p->x;
  2494.     ly = p->y;
  2495.     gdImageLine(im, lx, ly, p[n-1].x, p[n-1].y, c);
  2496.     for (i=1; (i < n); i++) {
  2497.         p++;
  2498.         gdImageLine(im, lx, ly, p->x, p->y, c);
  2499.         lx = p->x;
  2500.         ly = p->y;
  2501.     }
  2502. }    
  2503.     
  2504. int gdCompareInt(/* int *a, int *b */);
  2505.     
  2506. void gdImageFilledPolygon(im, p, n, c)
  2507.     gdImagePtr im;
  2508.     gdPointPtr p;
  2509.     int n;
  2510.     int c;
  2511. {
  2512.     int i;
  2513.     int y;
  2514.     int y1, y2;
  2515.     int ints;
  2516.     if (!n) {
  2517.         return;
  2518.     }
  2519.     if (!im->polyAllocated) {
  2520.         im->polyInts = (int *) malloc(sizeof(int) * n);
  2521.         im->polyAllocated = n;
  2522.     }        
  2523.     if (im->polyAllocated < n) {
  2524.         while (im->polyAllocated < n) {
  2525.             im->polyAllocated *= 2;
  2526.         }    
  2527.         im->polyInts = (int *) realloc(im->polyInts,
  2528.             sizeof(int) * im->polyAllocated);
  2529.     }
  2530.     y1 = p[0].y;
  2531.     y2 = p[0].y;
  2532.     for (i=1; (i < n); i++) {
  2533.         if (p[i].y < y1) {
  2534.             y1 = p[i].y;
  2535.         }
  2536.         if (p[i].y > y2) {
  2537.             y2 = p[i].y;
  2538.         }
  2539.     }
  2540.     for (y=y1; (y <= y2); y++) {
  2541.         int interLast;
  2542.         int dirLast;
  2543.         int interFirst = 1;
  2544.         ints = 0;
  2545.         for (i=0; (i <= n); i++) {
  2546.             int x1, x2;
  2547.             int y1, y2;
  2548.             int dir;
  2549.             int ind1, ind2;
  2550.             if ((i == n) || (!i)) {
  2551.                 ind1 = n-1;
  2552.                 ind2 = 0;
  2553.             } else {
  2554.                 ind1 = i-1;
  2555.                 ind2 = i;
  2556.             }
  2557.             y1 = p[ind1].y;
  2558.             y2 = p[ind2].y;
  2559.             if (y1 < y2) {
  2560.                 y1 = p[ind1].y;
  2561.                 y2 = p[ind2].y;
  2562.                 x1 = p[ind1].x;
  2563.                 x2 = p[ind2].x;
  2564.                 dir = -1;
  2565.             } else if (y1 > y2) {
  2566.                 y2 = p[ind1].y;
  2567.                 y1 = p[ind2].y;
  2568.                 x2 = p[ind1].x;
  2569.                 x1 = p[ind2].x;
  2570.                 dir = 1;
  2571.             } else {
  2572.                 /* Horizontal; just draw it */
  2573.                 gdImageLine(im, p[ind1].x, y1, p[ind2].x, y1);
  2574.                 continue;
  2575.             }
  2576.             if ((y >= y1) && (y <= y2)) {
  2577.                 int inter = 
  2578.                     (y-y1) * (x2-x1) / (y2-y1) + x1;
  2579.                 /* Only count intersections once
  2580.                     except at maxima and minima */
  2581.                 if (!interFirst) {
  2582.                     if (inter == interLast) {
  2583.                         if (dir == dirLast) {
  2584.                             continue;
  2585.                         }
  2586.                     }
  2587.                 } 
  2588.                 if (i > 0) {
  2589.                     im->polyInts[ints++] = inter;
  2590.                 }
  2591.                 dirLast = dir;
  2592.                 interLast = inter;
  2593.                 interFirst = 0;
  2594.             }
  2595.         }
  2596.         qsort(im->polyInts, ints, sizeof(int), gdCompareInt);
  2597.         for (i=0; (i < (ints-1)); i+=2) {
  2598.             gdImageLine(im, im->polyInts[i], y,
  2599.                 im->polyInts[i+1], y, c);
  2600.         }
  2601.     }
  2602. }
  2603.     
  2604. int gdCompareInt(a, b)
  2605.     int *a;
  2606.     int *b;
  2607. {
  2608.     return *a - *b;
  2609. }
  2610.  
  2611. void gdImageSetStyle(im, style, noOfPixels)
  2612.     gdImagePtr im;
  2613.     int *style; 
  2614.     int noOfPixels;
  2615. {
  2616.     if (im->style) {
  2617.         free(im->style);
  2618.     }
  2619.     im->style = (unsigned int *) 
  2620.         malloc(sizeof(unsigned int) * noOfPixels);
  2621.     memcpy(im->style, style, sizeof(unsigned int) * noOfPixels);
  2622.     im->styleLength = noOfPixels;
  2623.     im->stylePos = 0;
  2624. }
  2625.  
  2626. void gdImageSetBrush(im, brush)
  2627.     gdImagePtr im;
  2628.     gdImagePtr brush;
  2629. {
  2630.     int i;
  2631.     im->brush = brush;
  2632.     for (i=0; (i < gdImageColorsTotal(brush)); i++) {
  2633.         int index;
  2634.         index = gdImageColorExact(im, 
  2635.             gdImageRed(brush, i),
  2636.             gdImageGreen(brush, i),
  2637.             gdImageBlue(brush, i));
  2638.         if (index == (-1)) {
  2639.             index = gdImageColorAllocate(im,
  2640.                 gdImageRed(brush, i),
  2641.                 gdImageGreen(brush, i),
  2642.                 gdImageBlue(brush, i));
  2643.             if (index == (-1)) {
  2644.                 index = gdImageColorClosest(im,
  2645.                     gdImageRed(brush, i),
  2646.                     gdImageGreen(brush, i),
  2647.                     gdImageBlue(brush, i));
  2648.             }
  2649.         }
  2650.         im->brushColorMap[i] = index;
  2651.     }
  2652. }
  2653.     
  2654. void gdImageSetTile(im, tile)
  2655.     gdImagePtr im;
  2656.     gdImagePtr tile;
  2657. {
  2658.     int i;
  2659.     im->tile = tile;
  2660.     for (i=0; (i < gdImageColorsTotal(tile)); i++) {
  2661.         int index;
  2662.         index = gdImageColorExact(im, 
  2663.             gdImageRed(tile, i),
  2664.             gdImageGreen(tile, i),
  2665.             gdImageBlue(tile, i));
  2666.         if (index == (-1)) {
  2667.             index = gdImageColorAllocate(im,
  2668.                 gdImageRed(tile, i),
  2669.                 gdImageGreen(tile, i),
  2670.                 gdImageBlue(tile, i));
  2671.             if (index == (-1)) {
  2672.                 index = gdImageColorClosest(im,
  2673.                     gdImageRed(tile, i),
  2674.                     gdImageGreen(tile, i),
  2675.                     gdImageBlue(tile, i));
  2676.             }
  2677.         }
  2678.         im->tileColorMap[i] = index;
  2679.     }
  2680. }
  2681.  
  2682. void gdImageInterlace(im, interlaceArg) 
  2683.     gdImagePtr im;
  2684.     int interlaceArg;
  2685. {
  2686.     im->interlace = interlaceArg;
  2687. }
  2688.  
  2689.